﻿using System;
using System.Collections.Generic;
using System.IO;
using CI.Interfaces;
using System.Runtime.Serialization;
using CI.Organism;
using CI.Utils;


namespace CI.DAL
{
    /// <summary>
    /// XML DAL class, used to load, save the results to local storage in xml.
    /// </summary>
    public class XMLDAL : IDAL
    {

        /// <summary>
        /// Simulation environment
        /// </summary>
        private readonly SimEnv _simEnv = SimEnv.Instance;

        private static string GetDalFilePath(string environment)
        {
            return Path.Combine(ResourceFolders.UsersResourceFolder(), environment + ".DAL.xml");
        }

        /// <summary>
        /// Load into the hosting environment a environment
        /// </summary>
        /// <param name="environment">dal environment name to load</param>
        /// <param name="hostEnvironment">host environment</param>
        /// <param name="maxSaveCount">ignored</param>
        /// <param name="selectedOrganismsToLoad"></param>
        /// <returns>true if successfull</returns>
        public IHostingEnvironment LoadHostingEnvironment(string environment, IHostingEnvironment hostEnvironment, int maxSaveCount, List<Guid> selectedOrganismsToLoad)
        {
            #region Argument Checks
            if (string.IsNullOrEmpty(environment))
                throw new ArgumentException("environment");
            if (hostEnvironment == null)
                throw new ArgumentException("hostEnvironment");
            #endregion

            // see if we have the dal else exit
            if (!File.Exists(GetDalFilePath(environment)))
            {
                return null;
            }

            try
            {
                using (Stream sw = new FileStream(GetDalFilePath(environment), FileMode.Open, FileAccess.Read))
                {
                    var dataContractSerializer = new DataContractSerializer(hostEnvironment.GetType());
                    var hostEnvironmentPhysical = hostEnvironment.HostingEnvironmentPhysical;
                    var scenario = hostEnvironment.EnvironmentScenario;
                    hostEnvironment = (IHostingEnvironment)dataContractSerializer.ReadObject(sw);
                    hostEnvironment.HostingEnvironmentPhysical = hostEnvironmentPhysical;
                    _simEnv.HostEnv = hostEnvironment;
                    _simEnv.HostEnvPhysical = hostEnvironmentPhysical;
                    hostEnvironment.EnvironmentScenario = scenario;

                    // set them all to have a init energy and set the organism to point to the right collection they belong too
                    foreach (IOrganism organism in hostEnvironment.Organisms)
                    {
                        organism.Energy = organism.InitEnergy;
                        organism.CIET = organism.InitCIET;
                        organism.Organisms = hostEnvironment.Organisms;
                    }

                    // clear the dead list
                    hostEnvironment.Organisms.Dead.Clear();
                }
            }
            catch (Exception ex)
            {
                _simEnv.TraceLogger.LogException("Error Serializing data", ex);
                return null;
            }

            return hostEnvironment;
        }

        /// <summary>
        /// Save our organisms and environment to xml based on the environment
        /// </summary>
        /// <param name="environment">dal environment name to save</param>
        /// <param name="hostEnvironment">host environment</param>
        /// <param name="maxSaveCount">ignored</param>
        /// <returns>true if successfull</returns>
        public bool SaveHostingEnvironment(string environment, IHostingEnvironment hostEnvironment, int maxSaveCount)
        {

            #region Argument Checks
            if (string.IsNullOrEmpty(environment))
                throw new ArgumentException("environment");
            if (hostEnvironment == null)
                throw new ArgumentException("hostEnvironment");
            #endregion

            try
            {
                TrimWeakOrganisms(hostEnvironment);

                using (Stream sw = new FileStream(GetDalFilePath(environment), FileMode.Create, FileAccess.ReadWrite))
                {
                    var dataContractSerializer = new DataContractSerializer(hostEnvironment.GetType());
                    dataContractSerializer.WriteObject(sw, hostEnvironment);
                }
            }
            catch (Exception ex)
            {
                _simEnv.TraceLogger.LogException("Error Serializing data", ex);
                return false;
            }
            return true;
        }

        private static void TrimWeakOrganisms(IHostingEnvironment hostEnvironment)
        {
            var fittestList = DalFactory.CreateFittestList(hostEnvironment);
            hostEnvironment.Organisms.Alive.Clear();
            hostEnvironment.Organisms.Dead.Clear();
            hostEnvironment.Organisms.Inactive.Clear();

            foreach (IOrganism organism in fittestList)
            {
                hostEnvironment.Organisms.Alive.Add(organism);
            }

        }


    }
}
